package com.weituotian.system.service.impl;

import com.weituotian.core.jpa.domain.SimpleSpecification;
import com.weituotian.core.jpa.domain.Specification;
import com.weituotian.core.result.JsTreeNode;
import com.weituotian.core.utils.PageInfo;
import com.weituotian.system.dao.IBaseDao;
import com.weituotian.system.dao.IMenuDao;
import com.weituotian.system.dao.IResourceDao;
import com.weituotian.system.dao.mapper.Menu2JsTreeNodeMapper;
import com.weituotian.system.dao.mapper.MenuVoMapper;
import com.weituotian.system.entity.Menu;
import com.weituotian.system.entity.Resource;
import com.weituotian.system.entity.vo.MenuVo;
import com.weituotian.system.service.IMenuService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 菜单服务
 * Created by ange on 2016/9/26.
 */
@Service("menuService")
@Transactional
public class MenuService extends AdminBaseService<Menu, Integer> implements IMenuService {


    private final IMenuDao menuDao;

    private final IResourceDao resourceDao;

    private final MenuVoMapper mapper;

    @Autowired
    public MenuService(IMenuDao menuDao, MenuVoMapper mapper, IResourceDao resourceDao) {
        this.menuDao = menuDao;
        this.mapper = mapper;
        this.resourceDao = resourceDao;
    }


    @Override
    public IBaseDao<Menu, Integer> getBaseDao() {
        return menuDao;
    }

    @Override
    public Specification<Menu> pageSpecification(PageInfo<?> pageInfo) {

        return new SimpleSpecification<Menu>() {

            @Override
            public void beforeSelectList(Root<Menu> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                //fetch资源,一次性加载出来
                root.fetch("resource", JoinType.LEFT);

            }

            @Override
            public void onOrder(List<Order> orders, Root<Menu> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                if (pageInfo.getCondition().get("parent") != null) {
                    //按照关联的url排序
//                    orders.add(0, cb.asc(root.get("resource").get("url")));//放在list最前
                    orders.add(cb.asc(root.get("resource").get("url")));
                }
            }

            @Override
            public Predicate toPredicate(Root<Menu> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

                List<Predicate> predicates = new ArrayList<Predicate>();

                //拼接查询条件
                for (Map.Entry<String, Object> entry : pageInfo.getCondition().entrySet()) {
                    String name = entry.getKey();
                    String value = (String) entry.getValue();
                    if (name.equals("name")) {
                        predicates.add(cb.like(root.get("text"), "%" + value + "%"));
                    } else if (name.equals("parent")) {
                        //寻找这个父菜单的子菜单,包括父菜单本身
                        predicates.add(cb.or(cb.equal(root.get("pid"), value), cb.equal(root.get("id"), value)));
                    } else {
                        predicates.add(cb.equal(root.get(name), value));
                    }
                }

                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }

    private void setParentAndResource(Menu menu, Integer pid, Integer resourceId) {
        if (pid != null) {
            Menu pMenu = menuDao.findOne(pid);
            menu.setParent(pMenu);
        }
        if (resourceId != null) {
            Resource resource = resourceDao.findOne(resourceId);
            menu.setResource(resource);
        }
    }

    @Override
    public void addMenu(Menu menu, Integer pid, Integer resourceId) {
        setParentAndResource(menu, pid, resourceId);
        menuDao.persist(menu);
    }

    @Override
    public void updateMenu(Menu menu, Integer pid, Integer resourceId) {
        setParentAndResource(menu, pid, resourceId);
        menuDao.update(menu);
    }

    @Override
    public void findPageMenuVo(PageInfo<MenuVo> pageInfo) {
        findPageVo(MenuVo.class, pageInfo, mapper);
    }

    @Override
    public List<MenuVo> findAllMenuVo() {
        List<Menu> content = menuDao.findAllMenu();
        List<MenuVo> menuVos = (List<MenuVo>) mapper.toListDto(content);//转换为vo
        return menuVos;
    }

    @Override
    public List<MenuVo> findUserMenuVo() {
        Subject subject = SecurityUtils.getSubject();
        List<Menu> content = menuDao.findAllMenu();
        List<MenuVo> menuVos = new ArrayList<>();
        for (Menu menu : content) {
            if (menu.getResource() != null) {
                //菜单关联了资源的要检查权限
                String url = menu.getResource().getUrl();
                if (subject.isPermitted(url)) {
                    MenuVo vo = mapper.toDto(menu);
                    menuVos.add(vo);
                }
            }else {
                //没有关联资源
                MenuVo vo = mapper.toDto(menu);
                menuVos.add(vo);
            }
        }
        return menuVos;
    }

    @Override
    public List<JsTreeNode> findJsTreeNodeByPid(Integer pid) {
        /*Menu parentMenu = menuDao.findOne(pid);
        System.out.println("-----------findJsTreeNodeByPid------------");
        List<Menu> menus = parentMenu.getChildren();
        List<JsTreeNode> nodes = new ArrayList<>();
        for (Menu menu1 : menus) {
            JsTreeNode node = Menu2JsTreeNodeMapper.toJsTreeNode(menu1);
            if (menu1.getChildren().size() > 0) {
                node.setChildren(true);
            }
            nodes.add(node);
        }
        return nodes;*/
        return menuDao.findJsTreeNodeByPid(pid);
    }

    @Override
    public JsTreeNode findJsTreeNode(Integer id) {
        Menu menu = menuDao.findOne(id);
        return Menu2JsTreeNodeMapper.toJsTreeNode(menu);
    }

    @Override
    public List<JsTreeNode> findJsTreeRootNodes() {
        List<Menu> list = menuDao.findRootMenu();

        List<JsTreeNode> nodes = new ArrayList<>();
        for (Menu menu : list) {
            JsTreeNode node = Menu2JsTreeNodeMapper.toJsTreeNode(menu);
            node.setPid("-1");
            node.setChildren(true);
            nodes.add(node);
        }

        return nodes;
    }

}
